<<<<<<< .mine
﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Reflection;

using LINQToolKit.Mapping;

namespace LINQToolKit.Processors
{
    public class EntityProcessor : IXmlEntityProcessor
    {
        private IDictionary<Type, IXmlPropertyProcessor> _processors;

        public virtual bool Reuseable
        {
            get { return true; }
        }

        public EntityProcessor()
        {
            this._processors = new Dictionary<Type, IXmlPropertyProcessor>();
        }

        private IXmlPropertyProcessor GetProcessors(Type processorType)
        {
            if (!this._processors.ContainsKey(processorType))
            {
                var instance = (IXmlPropertyProcessor)Activator.CreateInstance(processorType);

                if (instance.Reuseable)
                {
                    this._processors.Add(processorType, instance);
                }

                return instance;
            }

            return this._processors[processorType];
        }

        private object GetPropertyValue(MetaProperty property, IEnumerable<XElement> nodes)
        {
            object propertyValue = null;

            if (nodes == null || nodes.Count() == 0)
            {
                return null;
            }

            if (property.Processor == null)
            {
                if (property.IsCollection)
                {
                    propertyValue = nodes.Select(n => n.Value);
                }
                else
                {
                    propertyValue = nodes.Select(n => n.Value).First();
                }
            }
            else
            {
                var processor = this.GetProcessors(property.Processor);
                propertyValue = processor.FromXml(property, nodes);
            }

            return propertyValue;
        }

        private static XmlNamespaceManager GetNSManager(MetaEntity model, XElement element)
        {
            var reader = element.CreateReader();
            var manager = new XmlNamespaceManager(reader.NameTable);
            reader.Close();

            foreach (var item in model.Namespaces)
            {
                manager.AddNamespace(item.Prefix, item.Uri);
            }

            return manager;
        }

        public virtual string ToInsertXml(MetaEntity model, object entity)
        {
            throw new NotImplementedException();
        }

        public virtual string ToUpdateXml(MetaEntity model, object entity)
        {
            throw new NotImplementedException();
        }

        public object ConvertOne(MetaEntity model, string entryXml)
        {
            entryXml.AssertNull("entryXml");
            model.AssertNull("model");

            return this.ConvertOne(model, XElement.Parse(entryXml));
        }

        public IEnumerable ConvertAll(MetaEntity model, string feedXml)
        {
            feedXml.AssertNull("feedXml");
            model.AssertNull("model");

            return this.ConvertAll(model, XElement.Parse(feedXml));
        }

        public virtual IEnumerable ConvertAll(MetaEntity model, XElement feed)
        {
            feed.AssertNull("feed");
            model.AssertNull("model");
            IList<XElement> entries = this.GetSubEntries(feed);

            if (entries.Count == 0)
            {
                return null;
            }

            var list = (IList)Activator.CreateInstance(
                typeof(List<>).MakeGenericType(model.Type));
            XmlNamespaceManager manager = GetNSManager(model, feed);

            foreach (var item in entries)
            {
                list.Add(this.Convert(model, item, manager));
            }

            return list;
        }

        protected virtual IList<XElement> GetSubEntries(XElement feed)
        {
            return feed.Elements().ToList();
        }

        private object Convert(MetaEntity model, XElement entry, XmlNamespaceManager manager)
        {
            var entity = Activator.CreateInstance(model.Type);
            entity.AssertNull(model.Type.AssemblyQualifiedName);
            // initializing the entity
            this.InitializeProperties(model, entity, entry, manager);
            this.InitializeAssociations(model, entity, entry, manager);

            return entity;
        }

        public virtual object ConvertOne(MetaEntity model, XElement entry)
        {
            entry.AssertNull("entry");
            model.AssertNull("model");
            XmlNamespaceManager manager = GetNSManager(model, entry);

            return this.Convert(model, entry, manager);
        }

        private void InitializeProperties(
            MetaEntity model, object entity, XElement element, XmlNamespaceManager manager)
        {
            foreach (var p in model.Properties)
            {
                var propertyInfo = model.Type.GetProperty(p.Name);
                propertyInfo.AssertNull(p.Name, "cannot find property definition");
                var nodes = element.XPathSelectElements(p.Path, manager);
                var propertyValue = this.GetPropertyValue(p, nodes);
                propertyInfo.SetValue(entity, propertyValue, null);
            }
        }

        private void InitializeAssociations(
            MetaEntity model, object entity, XElement element, XmlNamespaceManager manager)
        {
            foreach (var ass in model.Associations)
            {
                var propertyInfo = model.Type.GetProperty(ass.Name);
                propertyInfo.AssertNull(ass.Name, "cannot find association definition");
                var keyValue = string.Empty;
                Uri source = null;

                if (!string.IsNullOrEmpty(ass.Key))
                {
                    var keyprop = model.Type.GetProperty(
                        ass.Key, BindingFlags.Instance | BindingFlags.Public);
                    keyprop.AssertNull(ass.Key, "cannot find defition for association key");

                    keyValue = keyprop.GetValue(entity, null).ToString();
                }

                if (ass.IsRelativeSource)
                {
                    var node = element.XPathSelectElement(ass.Source, manager);
                    //node.AssertNull(ass.Source, "cannot find the definition for assocation source");
                    source = node == null ? 
                        new Uri("http://127.0.0.1") : new Uri(string.Format(node.Value, keyValue));
                }
                else
                {
                    source = new Uri(string.Format(ass.Source, keyValue));
                }

                object assObj = Activator.CreateInstance(propertyInfo.PropertyType, source);
                propertyInfo.SetValue(entity, assObj, null);
            }
        }
    }
}
=======
﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Reflection;

using LINQToolKit.Mapping;

namespace LINQToolKit.Processors
{
    public class EntityProcessor : IXmlEntityProcessor
    {
        private IDictionary<Type, IXmlPropertyProcessor> _processors;

        public virtual bool Reuseable
        {
            get { return true; }
        }

        public EntityProcessor()
        {
            this._processors = new Dictionary<Type, IXmlPropertyProcessor>();
        }

        private IXmlPropertyProcessor GetProcessors(Type processorType)
        {
            if (!this._processors.ContainsKey(processorType))
            {
                var instance = (IXmlPropertyProcessor)Activator.CreateInstance(processorType);

                if (instance.Reuseable)
                {
                    this._processors.Add(processorType, instance);
                }

                return instance;
            }

            return this._processors[processorType];
        }

        private object GetPropertyValue(MetaProperty property, IEnumerable<XElement> nodes)
        {
            object propertyValue = null;

            if (nodes == null || nodes.Count() == 0)
            {
                return null;
            }

            if (property.Processor == null)
            {
                if (property.IsCollection)
                {
                    propertyValue = nodes.Select(n => n.Value);
                }
                else
                {
                    propertyValue = nodes.Select(n => n.Value).First();
                }
            }
            else
            {
                var processor = this.GetProcessors(property.Processor);
                propertyValue = processor.FromXml(property, nodes);
            }

            return propertyValue;
        }

        private static XmlNamespaceManager GetNSManager(MetaEntity model, XElement element)
        {
            var reader = element.CreateReader();
            var manager = new XmlNamespaceManager(reader.NameTable);
            reader.Close();

            foreach (var item in model.Namespaces)
            {
                manager.AddNamespace(item.Prefix, item.Uri);
            }

            return manager;
        }

        public virtual string ToInsertXml(MetaEntity model, object entity)
        {
            throw new NotImplementedException();
        }

        public virtual string ToUpdateXml(MetaEntity model, object entity)
        {
            throw new NotImplementedException();
        }

        public object ConvertOne(MetaEntity model, string entryXml)
        {
            entryXml.AssertNull("entryXml");
            model.AssertNull("model");

            return this.ConvertOne(model, XElement.Parse(entryXml));
        }

        public IList ConvertAll(MetaEntity model, string feedXml)
        {
            feedXml.AssertNull("feedXml");
            model.AssertNull("model");

            return this.ConvertAll(model, XElement.Parse(feedXml));
        }

        public virtual IList ConvertAll(MetaEntity model, XElement feed)
        {
            feed.AssertNull("feed");
            model.AssertNull("model");
            IList<XElement> entries = this.GetSubEntries(feed);

            if (entries.Count == 0)
            {
                return null;
            }

            var list = (IList)Activator.CreateInstance(
                typeof(List<>).MakeGenericType(model.Type));
            XmlNamespaceManager manager = GetNSManager(model, feed);

            foreach (var item in entries)
            {
                list.Add(this.Convert(model, item, manager));
            }

            return list;
        }

        protected virtual IList<XElement> GetSubEntries(XElement feed)
        {
            return feed.Elements().ToList();
        }

        private object Convert(MetaEntity model, XElement entry, XmlNamespaceManager manager)
        {
            var entity = Activator.CreateInstance(model.Type);
            entity.AssertNull(model.Type.AssemblyQualifiedName);
            // initializing the entity
            this.InitializeProperties(model, entity, entry, manager);
            this.InitializeAssociations(model, entity, entry, manager);

            return entity;
        }

        public virtual object ConvertOne(MetaEntity model, XElement entry)
        {
            entry.AssertNull("entry");
            model.AssertNull("model");
            XmlNamespaceManager manager = GetNSManager(model, entry);

            return this.Convert(model, entry, manager);
        }

        private void InitializeProperties(
            MetaEntity model, object entity, XElement element, XmlNamespaceManager manager)
        {
            foreach (var p in model.Properties)
            {
                var propertyInfo = model.Type.GetProperty(p.Name);
                propertyInfo.AssertNull(p.Name, "cannot find property definition");
                var nodes = element.XPathSelectElements(p.Path, manager);
                var propertyValue = this.GetPropertyValue(p, nodes);
                propertyInfo.SetValue(entity, propertyValue, null);
            }
        }

        private void InitializeAssociations(
            MetaEntity model, object entity, XElement element, XmlNamespaceManager manager)
        {
            foreach (var ass in model.Associations)
            {
                var propertyInfo = model.Type.GetProperty(ass.Name);
                propertyInfo.AssertNull(ass.Name, "cannot find association definition");
                var keyValue = string.Empty;
                Uri source = null;

                if (!string.IsNullOrEmpty(ass.Key))
                {
                    var keyprop = model.Type.GetProperty(
                        ass.Key, BindingFlags.Instance | BindingFlags.Public);
                    keyprop.AssertNull(ass.Key, "cannot find defition for association key");

                    keyValue = keyprop.GetValue(entity, null).ToString();
                }

                if (ass.IsRelativeSource)
                {
                    var node = element.XPathSelectElement(ass.Source, manager);
                    //node.AssertNull(ass.Source, "cannot find the definition for assocation source");
                    source = node == null ? 
                        new Uri("http://127.0.0.1") : new Uri(string.Format(node.Value, keyValue));
                }
                else
                {
                    source = new Uri(string.Format(ass.Source, keyValue));
                }

                object assObj = Activator.CreateInstance(propertyInfo.PropertyType, source);
                propertyInfo.SetValue(entity, assObj, null);
            }
        }
    }
}
>>>>>>> .r48
